package com.proxy.scanandcheck.scaner.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.proxy.scanandcheck.checker.controller.ProxyCheckingController;
import com.proxy.scanandcheck.common.util.Constants;
import com.proxy.scanandcheck.common.valueobject.Proxy;
import com.proxy.scanandcheck.common.valueobject.ProxyRequest;
import com.proxy.scanandcheck.scaner.dao.ScannerDao;
import com.proxy.scanandcheck.scaner.valueobject.IpAddress;

@Service
public class ScannerThreadPool {
	
	private static final Logger LOGGER = Logger.getLogger(ScannerThreadPool.class);
	
	private ThreadPoolExecutor threadPoolExecutor;
	
	@Autowired
	private ScannerDao scannerDao;
	
	@Autowired
	private ProxyCheckingController proxyCheckingController;
	
	public boolean execute(ProxyRequest proxyRequest) throws InterruptedException, ExecutionException
	{
//		ExecutorService threadPool = Executors.newCachedThreadPool();
		
		threadPoolExecutor = new ThreadPoolExecutor(proxyRequest.getThreadCount(), 
				Integer.MAX_VALUE, Constants.KEEP_ALIVE_TIME,
				TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000),
				new ThreadPoolExecutor.CallerRunsPolicy());
		
		/*List<Scanner> tasks = new ArrayList<Scanner>();
		
		for (int i = 0; i < 1000000; i++) {
//			threadPool.submit(new Scanner("google.com", i));
			tasks.add(new Scanner("google.com", i));
		}
		threadPool.invokeAll(tasks);*/
		
		int length = 1000;
		int index = 0;
		int startIndex, endIndex;
		while(true)
		{
			startIndex = length * index;
			endIndex = length * (index + 1);
			
			List<IpAddress> ipAddressList = scannerDao.getIpAddressList(proxyRequest, startIndex, endIndex);
			List<ScannerThreadPoolTask> scannerThreadPoolTaskList = new ArrayList<ScannerThreadPoolTask>();
			for(IpAddress ipAddress: ipAddressList)
			{
				ScannerThreadPoolTask scannerThreadPoolTask = new ScannerThreadPoolTask(ipAddress);
				scannerThreadPoolTaskList.add(scannerThreadPoolTask);
			}
			LOGGER.info("------ Scan from " + 
						ipAddressList.get(0) + 
						" - " + 
						ipAddressList.get(ipAddressList.size() - 1) + 
						", size: " + 
						ipAddressList.size());
			threadPoolExecutor.invokeAll(scannerThreadPoolTaskList);
			
			proxyCheckingController.startCheck(
					getProxyList(ipAddressList), 
					proxyRequest.getKeyWordsList());
			
			if(endIndex > 100000)
			{
				break;
			}
			index ++;
			Thread.sleep(100);
		}
		
		/*List<Future<Boolean>> list = threadPoolTaskExecutor.invokeAll(tasks);
		for(int i = 0; i < tasks.size(); i++) {
		    if (list.get(i).get()) {
		        System.out.printf("Port is in use: %d", tasks.get(i).getPort());
		    } else {
		        System.out.printf("Port is not in use: %d", tasks.get(i).getPort());
		    }
		}*/
		return Boolean.TRUE;
	}
	
	private List<Proxy> getProxyList(List<IpAddress> ipAddressList)
	{
		List<Proxy> myProxyList = new ArrayList<Proxy>();
		for(IpAddress ipAddress : ipAddressList)
		{
			if(ipAddress.isValid())
			{
				Proxy proxy = new Proxy();
				proxy.setProxy(ipAddress.getAddress() + ":" + ipAddress.getPort());
				proxy.setIpClass(ipAddress.getIpClass());
				proxy.setUpdateTimeForGoogleHost(ipAddress.getUpdateTime());
				myProxyList.add(proxy);
				LOGGER.info("------ valid ip after scan: " + ipAddress);
			}
		}
		if(myProxyList.isEmpty())
		{
			String msg = "------ can't find valid ip after scan: " +
					ipAddressList.get(0) +
					" -- " + 
					ipAddressList.get(ipAddressList.size() - 1);
			LOGGER.info(msg);
		}
		return myProxyList;
	}
	
	public void shutdowThread()
	{
		// dont forget to shutdown executor
		if(threadPoolExecutor != null)
		{
			threadPoolExecutor.shutdown();
			threadPoolExecutor = null;
			/*try {
				// Wait for everything to finish.
				while (!threadPool.awaitTermination(2, TimeUnit.SECONDS)) {
//				System.out.println("Awaiting completion of threads.");
					Thread.sleep(100);
				}
				System.out.println("finished scanning port");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}*/
		}
	}

}
